package org.springboot.rabbitmq.controller;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/rabbit")
public class RabbitController {

	@Autowired 
	@Qualifier("mainRabbitTemplate")
    RabbitTemplate mainRabbitTemplate;

	/**
	 * Rabbit Management 默认账户 guest/guest
	 */

	/**
	 * AMQP（高级消息队列协议，网络协议）: 
	 *   支持符合要求的客户端应用(application)和消息中间件代理(messaging middleware broker)之间进行通信 
	 * 消息代理(message brokers): 
	 *   从发布者(publishers)亦称生产者(producers)接收消息，并根据既定的路由规则把接收到的消息发送给处理消息的消费者(consumers)  
	 * 消息确认(message acknowledgements): 
	 *   一个消息从队列中投递给消费者后(consumer)，消费者会通知一下消息代理(broker)，可以是自动的也可以由处理消息的应用的开发者执行。
	 * 当"消息确认"被启用的时候，消息代理不会完全将消息从队列中删除，直到它收到来自消费者的确认回执(acknowledgement)
	 * 
	 * 交换机类型: (交换机拿到一个消息之后将它路由给一个或零个队列。使用哪种路由算法是由交换机类型和被称作绑定(bindings)的规则所决定的)
	 *  - Direct exchange（直连交换机）
	 *  - Fanout exchange（扇型交换机）
	 *  - Topic exchange（主题交换机）
	 *  - Headers exchange（头交换机）
	 * 交换机属性: 
	 *  - Name
	 *  - Durability（消息代理重启后，交换机是否还存在）
	 *  - Auto-delete（当所有与之绑定的消息队列都完成了对此交换机的使用后，删掉它）
	 *  - Arguments（依赖代理本身）
	 *  
	 *  队列属性(queue): 
	 *   - Name
	 *   - Durable（消息代理重启后，队列依旧存在）
	 *   - Exclusive（只被一个连接(connection)使用，而且当连接关闭后队列即被删除）
	 *   - Auto-delete（当最后一个消费者退订后即被删除）
	 *   - Arguments（一些消息代理用他来完成类似与 TTL 的某些额外功能）
	 *    队列在声明(declare)后才能被使用。如果一个队列尚不存在，声明一个队列会创建它。如果声明的队列已经存在，并且属性完全相同，那么
	 *  此次声明不会对原有队列产生任何影响。如果声明中的属性与已存在队列的属性有差异，那么一个错误代码为 406 的通道级异常就会被抛出
	 *    以"amq."开始的队列名称被预留做消息代理内部使用。如果声明时违反会抛出一个通道级的 403(ACCESS_REFUSED)错误 
	 *    持久化队列(Durable queues)会被存储在磁盘上，当消息代理(broker)重启的时候，它依旧存在。没有被持久化的队列称作
	 *  暂存队列(Transient queues)。持久化的队列并不会使得路由到它的消息也具有持久性。
	 *  
	 *  绑定(Binding): 
	 *    交换机(exchange)将消息(message)路由给队列(queue)所需遵循的规则。如果要指示交换机"E"将消息路由给队列"Q"，那么"Q"就
	 *  需要与"E"进行绑定。绑定操作需要定义一个可选的路由键(routing key)属性给某些类型的交换机。路由键的意义在于从发送给交换机的众多
	 *  消息中选择出某些消息，将其路由给绑定的队列
	 */

	@RequestMapping(value = "/send")
    public String send(String message) {
		if (ObjectUtils.isEmpty(message)) {
			return "Please enter message!";
		}
		if ("spring-boot".equals(message)) {
			mainRabbitTemplate.convertAndSend(message, "Message content: " + message);
		} else if ("direct-1".equals(message)) {
			mainRabbitTemplate.convertAndSend("direct", "orange", "Message content: " + message);
		} else if ("direct-2".equals(message)) {
			mainRabbitTemplate.convertAndSend("direct", "black", "Message content: " + message);
			mainRabbitTemplate.convertAndSend("direct", "green", "Message content: " + message);
		} else if ("fanout-1".equals(message)) {
			mainRabbitTemplate.convertAndSend("fanout", "", "Message content: " + message);
		} else if ("fanout-2".equals(message)) {
			mainRabbitTemplate.convertAndSend("fanout", "", "Message content: " + message);
		} else if ("topic-1".equals(message)) {
			mainRabbitTemplate.convertAndSend("topic", "a.orange.c", "Message content: " + message);
		} else if ("topic-2".equals(message)) {
			mainRabbitTemplate.convertAndSend("topic", "lazy.123", "Message content: " + message);
			mainRabbitTemplate.convertAndSend("topic", "a.b.rabbit", "Message content: " + message);
		} else {
			return "Message error: " + message;
		}
		return "success";
	}

}
